import asyncio
import aiohttp
from minio import Minio
from minio.error import S3Error
from typing import Dict, Any, List, Optional
from io import BytesIO

from .storage_base import BaseStorageService, StorageResponse, FileType, StorageProvider

class MinIOStorageService(BaseStorageService):
    """MinIO对象存储服务实现"""
    
    def __init__(self, config: Dict[str, Any]):
        super().__init__(config)
        self.endpoint = config.get("endpoint", "localhost:9000")
        self.access_key = config.get("access_key")
        self.secret_key = config.get("secret_key")
        self.secure = config.get("secure", False)
        
        # 初始化MinIO客户端
        self.client = Minio(
            endpoint=self.endpoint,
            access_key=self.access_key,
            secret_key=self.secret_key,
            secure=self.secure
        )
        
        # 确保bucket存在
        asyncio.create_task(self._ensure_bucket_exists())
    
    async def _ensure_bucket_exists(self):
        """确保bucket存在"""
        try:
            if not self.client.bucket_exists(self.bucket_name):
                self.client.make_bucket(self.bucket_name)
                
                # 设置bucket策略为公开读取
                policy = {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Principal": {"AWS": "*"},
                            "Action": ["s3:GetObject"],
                            "Resource": [f"arn:aws:s3:::{self.bucket_name}/*"]
                        }
                    ]
                }
                import json
                self.client.set_bucket_policy(self.bucket_name, json.dumps(policy))
        except Exception as e:
            print(f"创建bucket失败: {e}")
    
    async def upload_file(
        self, 
        file_data: bytes, 
        file_name: str, 
        file_type: FileType,
        content_type: str = "application/octet-stream"
    ) -> StorageResponse:
        """上传文件到MinIO"""
        try:
            file_key = self.generate_file_key(file_name, file_type)
            
            # 使用BytesIO包装字节数据
            file_stream = BytesIO(file_data)
            
            # 上传文件
            result = self.client.put_object(
                bucket_name=self.bucket_name,
                object_name=file_key,
                data=file_stream,
                length=len(file_data),
                content_type=content_type
            )
            
            # 生成访问URL
            if self.secure:
                file_url = f"https://{self.endpoint}/{self.bucket_name}/{file_key}"
            else:
                file_url = f"http://{self.endpoint}/{self.bucket_name}/{file_key}"
            
            return StorageResponse(
                success=True,
                file_url=file_url,
                file_key=file_key,
                metadata={
                    "provider": "minio",
                    "bucket": self.bucket_name,
                    "etag": result.etag,
                    "size": len(file_data)
                }
            )
            
        except S3Error as e:
            return StorageResponse(
                success=False,
                error_message=f"MinIO上传失败: {e}"
            )
        except Exception as e:
            return StorageResponse(
                success=False,
                error_message=f"文件上传失败: {e}"
            )
    
    async def upload_from_url(
        self, 
        source_url: str, 
        file_name: str, 
        file_type: FileType
    ) -> StorageResponse:
        """从URL下载文件并上传到MinIO"""
        try:
            async with aiohttp.ClientSession() as session:
                async with session.get(source_url) as response:
                    if response.status == 200:
                        file_data = await response.read()
                        content_type = response.headers.get("content-type", "application/octet-stream")
                        
                        return await self.upload_file(file_data, file_name, file_type, content_type)
                    else:
                        return StorageResponse(
                            success=False,
                            error_message=f"下载文件失败，状态码: {response.status}"
                        )
        except Exception as e:
            return StorageResponse(
                success=False,
                error_message=f"从URL上传失败: {e}"
            )
    
    async def delete_file(self, file_key: str) -> bool:
        """删除文件"""
        try:
            self.client.remove_object(self.bucket_name, file_key)
            return True
        except Exception as e:
            print(f"删除文件失败: {e}")
            return False
    
    async def get_file_url(self, file_key: str, expires: int = 3600) -> Optional[str]:
        """获取文件访问URL"""
        try:
            # 对于公开的bucket，直接返回URL
            if self.secure:
                return f"https://{self.endpoint}/{self.bucket_name}/{file_key}"
            else:
                return f"http://{self.endpoint}/{self.bucket_name}/{file_key}"
        except Exception as e:
            print(f"生成文件URL失败: {e}")
            return None
    
    async def list_files(self, prefix: str = "", limit: int = 100) -> List[Dict[str, Any]]:
        """列出文件"""
        try:
            objects = self.client.list_objects(
                self.bucket_name, 
                prefix=prefix, 
                recursive=True
            )
            
            files = []
            count = 0
            for obj in objects:
                if count >= limit:
                    break
                    
                files.append({
                    "key": obj.object_name,
                    "size": obj.size,
                    "last_modified": obj.last_modified.isoformat(),
                    "etag": obj.etag
                })
                count += 1
            
            return files
        except Exception as e:
            print(f"列出文件失败: {e}")
            return []